package demo;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * @Author liangbaigao
 * @Date 2023/9/19 14:32
 */
public class SingleModel {

    /**
     * 饿汉式-单例模式
     *  在类加载加载期间，初始化私有静态实例，保证线程安全
     */
    static class Hungry{

        private Hungry(){}

        private static Hungry hungry = new Hungry();

        public static Hungry getInstance(){
            return hungry;
        }
    }

    /**
     * 懒汉式-单例模式
     *  非线程安全
     */
    static class Lazy{
        private Lazy(){}

        private static Lazy lazy;

        public static Lazy getInstance(){
            if (lazy == null){
                return lazy = new Lazy();
            }
            return lazy;
        }
    }

    /**
     * 懒汉式-单例模式
     *  线程安全
     */
    static class Lazy2{

        private Lazy2(){}

        private static Lazy2 lazy;

        public static synchronized Lazy2 getInstance(){
            if (lazy == null){
                return lazy = new Lazy2();
            }
            return lazy;
        }
    }

    /**
     * 双重校验
     */
    static class DoubleCheck{

        private DoubleCheck(){};

        private static volatile DoubleCheck instance;

        public static DoubleCheck getInstance(){
            if( instance == null){
                synchronized (DoubleCheck.class){
                    if(instance == null){
                        instance = new DoubleCheck();
                    }
                }
            }
            return instance;
        }
    }




    /**
     * 静态内部类
     *  同时解决 线程安全 ，延时加载问题
     */
    static class StaticInnerClass{
        private StaticInnerClass(){};

        private static class InnerClass{
            private static volatile StaticInnerClass instance
                    = new StaticInnerClass();
        }

        public static StaticInnerClass getInstance(){
            return InnerClass.instance;
        }

    }


    /**
     * 反射对单例模式的破坏
     */
    public static void reflectDestroy(){
        try{
            // 反射对单例的破坏
            Class<StaticInnerClass> clazz = StaticInnerClass.class;
            Constructor<StaticInnerClass> c = clazz.getDeclaredConstructor();
            c.setAccessible(true);

            StaticInnerClass instance1 = c.newInstance();
            StaticInnerClass instance2 = c.newInstance();

            // false
            System.out.println(instance1 == instance2);

        /* 非优雅解决,破坏代码简洁
         private StaticInnerClass(){
             if (instance != null){
                 throw new RuntimeException("不允许非法访问");
             }
         };
        */
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 单例类实现序列化接口
     */
    public static class Singleton implements Serializable {

        private volatile static Singleton singleton;

        private Singleton() {

        }

        public static Singleton getInstance() {
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }

        /**
         * 解决方案:只要在Singleton类中定义readResolve就可以解决该问题
         * 程序会判断是否有readResolve方法,如果存在就在执行该方法,如果不存在--就创建一个对象
         */
        private Object readResolve() {
            return singleton;
        }

    }

    /**
     * 序列化对单例模式的破坏
     */
    public static void serializationDestroy() throws Exception {
        //序列化对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile.obj"));
        oos.writeObject(Singleton.getInstance());

        //序列化对象输入流
        File file = new File("tempFile.obj");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        Singleton Singleton = (Singleton) ois.readObject();

        System.out.println(Singleton);
        System.out.println(SingleModel.Singleton.getInstance());

        //判断是否是同一个对象 //false
        System.out.println(SingleModel.Singleton.getInstance() == Singleton);
    }

    /**
     * 枚举方式 - 推荐
     *  因为枚举没有 无参构造方法，当在构造时
     *   反射不允许构造枚举类
     *
     */
    enum SingletonEnum {

        INSTANCE;

        private Object data;


        public Object getData() {
            return data;
        }

        public void setData(Object data) {
            this.data = data;
        }

        public SingletonEnum getInstance(){
            return INSTANCE;
        }
    }


    public static void main(String[] args) throws Exception {


        // 反射对单例模式的破坏
        reflectDestroy();

        // 序列化对单例模式的破坏
        serializationDestroy();

    }






}
